home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume4 / nums < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  9.2 KB

  1. Subject: list-of-numbers generator
  2. Newsgroups: mod.sources
  3. Approved: jpn@panda.UUCP
  4.  
  5. Mod.sources:  Volume 4, Issue 53
  6. Submitted by: hplabs!hpfcla!ajs (Alan Silverstein)
  7.  
  8. Greetings.  Here's an almost-ultimate (?) implementation of a list-of-numbers
  9. generator.  It's carefully coded, proof-read, tested, and documented.  Of
  10. course I've only run it on local systems (HP9000s), so I can't guarantee
  11. ultimate portability.
  12.  
  13.  [
  14.    It uses the new system V random number generator functions - srand48 and
  15.    lrand48.  You should be able to replace srand48() with srand, and lrand48
  16.    with rand() to make this run on most other systems.
  17.                    - John Nelson, Moderator
  18.  ]
  19.  
  20. Alan Silverstein, Hewlett-Packard Fort Collins Systems Division, Colorado
  21. {ihnp4 | hplabs}!hpfcla!ajs, 303-226-3800 x3053, N 40 31'31" W 105 00'43"
  22.  
  23.  
  24. #! /bin/sh
  25. # This is a shell archive, meaning:
  26. # 1. Remove everything above the #! /bin/sh line.
  27. # 2. Save the resulting text in a file.
  28. # 3. Execute the file with /bin/sh (not csh) to create the files:
  29. #    nums.1
  30. #    nums.c
  31. # This archive created: Mon Apr  7 11:47:53 1986
  32. export PATH; PATH=/bin:$PATH
  33. echo shar: extracting "'nums.1'" '(2704 characters)'
  34. if test -f 'nums.1'
  35. then
  36.     echo shar: will not over-write existing file "'nums.1'"
  37. else
  38. cat << \SHAR_EOF > 'nums.1'
  39. .TH NUMS 1 "HP Experimental"
  40. .ad b
  41. .SH NAME
  42. nums \- print a list of numbers
  43. .SH SYNOPSIS
  44. .B nums
  45. [
  46. .B \-lr
  47. ] [
  48. .BI \-s \0size
  49. ] [
  50. .BI \-w \0width
  51. ]
  52. .I value
  53. [
  54. .I value2
  55. ]
  56. .SH DESCRIPTION
  57. This command prints to standard output all integer values from 1 to
  58. .IR value ,
  59. or if you give two numbers, from
  60. .I value
  61. to
  62. .IR value2 ,
  63. one number per output line.
  64. If
  65. .I value
  66. alone is less than 1, or
  67. .I value2
  68. is less than
  69. .IR value ,
  70. it steps backwards rather than forwards.
  71. .PP
  72. This command may be useful with "for" loops in shell scripts
  73. (see example below)
  74. or for generating column headers or row numbers
  75. before adding text in an editor.
  76. .PP
  77. Options are:
  78. .TP
  79. .B \-l
  80. Print all output numbers on a single line,
  81. i.e. follow each except the last with a blank instead of a newline.
  82. .TP
  83. .B \-r
  84. Print the numbers in random order.
  85. A random number generator is seeded to the time plus
  86. process number plus real userid plus real groupid.
  87. Then successive random values are used to index into an array with one
  88. entry for each output value.
  89. When the index is of a value already printed,
  90. the program searches backward (with wrap-around)
  91. for the previous not-yet-printed number,
  92. so it terminates in a predictable time.
  93. .TP
  94. .BI \-s \0size
  95. Set the step size (increment) to a non-zero integer (default = 1).
  96. Starting with the first value,
  97. the program steps either forwards or backwards by the given
  98. .IR size ,
  99. as appropriate, until it passes the second value.
  100. The sign of
  101. .I size
  102. is irrelevant;
  103. the direction is determined by the given value(s).
  104. .TP
  105. .BI \-w \0width
  106. Right-justify output numbers in fields of at least the given width (columns)
  107. by padding with leading blanks as necessary.
  108. If
  109. .I width
  110. is negative, numbers are left-justified.
  111. .PP
  112. Separate options from
  113. .I value
  114. with "\fB--\fR" if 
  115. .I value
  116. is negative.
  117. .SH EXAMPLES
  118. .TP
  119. num 5
  120. Print five lines containing the numbers 1, 2, 3, 4, and 5.
  121. .TP
  122. num \-l \-w4 \-\- -1 3
  123. Print the numbers -1, 0, 1, 2, and 3 on a single line,
  124. each in a field four columns wide (plus leading blank separators), e.g.:
  125. .nf
  126. .RS
  127.  
  128. \0\0-1 \0\0\00 \0\0\01 \0\0\02 \0\0\03
  129. .RE
  130. .fi
  131. .TP
  132. num \-rs10 42
  133. Print the numbers 1, 11, 21, 31, and 41 in random order.
  134. .PP
  135. .nf
  136.  
  137. for n in `num 20 5`
  138. do
  139.     whatever
  140. done
  141. .PD 0
  142. .IP ""
  143. Do "whatever" 16 times, with "n" set to 20, 19, ..., 5.
  144. .PD
  145. .SH SEE ALSO
  146. xargs(1), time(2), getpid(2), getuid(2), getgid(2), drand48(3c)
  147. .SH DIAGNOSTICS
  148. Prints a message to standard error and exits non-zero if
  149. invoked wrong or it can't calloc() needed memory for the
  150. .B \-r
  151. option.
  152. .SH LIMITATIONS
  153. It doesn't understand real numbers.
  154. .PP
  155. If the number of numbers printed is not an integer divisor of the range of
  156. the random number generator,
  157. the output is not "precisely" random.
  158. SHAR_EOF
  159. if test 2704 -ne "`wc -c < 'nums.1'`"
  160. then
  161.     echo shar: error transmitting "'nums.1'" '(should have been 2704 characters)'
  162. fi
  163. fi
  164. echo shar: extracting "'nums.c'" '(4958 characters)'
  165. if test -f 'nums.c'
  166. then
  167.     echo shar: will not over-write existing file "'nums.c'"
  168. else
  169. cat << \SHAR_EOF > 'nums.c'
  170. /*
  171.  * Print a list of numbers.
  172.  * See the manual entry for details.
  173.  */
  174.  
  175. #include <stdio.h>
  176.  
  177.  
  178. /*********************************************************************
  179.  * MISCELLANEOUS GLOBAL VALUES:
  180.  */
  181.  
  182. #define    PROC                /* null; easy to find procs */
  183. #define    FALSE    0
  184. #define    TRUE    1
  185. #define    CHNULL    ('\0')
  186. #define    CPNULL    ((char *) NULL)
  187. #define    REG    register
  188.  
  189. char *usage[] = {
  190.     "usage: %s [-lr] [-s size] [-w width] value [value2]",
  191.     "-l print all one one line (default: one number per line)",
  192.     "-r print numbers in random order",
  193.     "-s set step size (increment, default = 1)",
  194.     "-w print numbers in fields of given width (default: no padding)",
  195.     "Prints numbers from 1 to value, or value to value2",
  196.     CPNULL,
  197. };
  198.  
  199. char    *myname;            /* how program was invoked    */
  200.  
  201. int    lflag = FALSE;            /* -l (all one line) option    */
  202. int    rflag = FALSE;            /* -r (randomize) option    */
  203.  
  204. int    step  = 1;            /* value from -s option        */
  205. int    width = 0;            /* value from -w option        */
  206.  
  207.  
  208. /************************************************************************
  209.  * M A I N
  210.  */
  211.  
  212. PROC main (argc, argv)
  213.     int    argc;
  214.     char    **argv;
  215. {
  216. extern    int    optind;            /* from getopt()    */
  217. extern    char    *optarg;        /* from getopt()    */
  218. REG    int    option;            /* option "letter"    */
  219. REG    int    value1 = 1;        /* first value        */
  220. REG    int    value2;            /* second value        */
  221.     char    format [20];        /* for printing numbers    */
  222. REG    char    sep;            /* leading separator    */
  223.  
  224. /*
  225.  * PARSE ARGUMENTS:
  226.  */
  227.  
  228.     myname = *argv;
  229.  
  230.     while ((option = getopt (argc, argv, "lrs:w:")) != EOF)
  231.     {
  232.         switch (option)
  233.         {
  234.         case 'l':    lflag = TRUE;    break;
  235.         case 'r':    rflag = TRUE;    break;
  236.  
  237.         case 's':    step  = atoi (optarg);  break;
  238.         case 'w':    width = atoi (optarg);  break;
  239.  
  240.         default:    Usage();
  241.         }
  242.     }
  243.  
  244.     argc -= optind;            /* skip options    */
  245.     argv += optind;
  246.  
  247. /*
  248.  * MORE ARGUMENT CHECKS:
  249.  */
  250.  
  251.     if (argc == 1)
  252.     {
  253.         value2 = atoi (argv [0]);
  254.     }
  255.     else if (argc == 2)
  256.     {
  257.         value1 = atoi (argv [0]);
  258.         value2 = atoi (argv [1]);
  259.     }
  260.     else
  261.     {
  262.         Usage();
  263.     }
  264.  
  265.     if (step == 0)
  266.         Error ("step size cannot be zero");
  267.  
  268. /*
  269.  * FINISH INITIALIZING:
  270.  */
  271.  
  272.     if (((step < 0) && (value1 < value2))
  273.      || ((step > 0) && (value1 > value2)))    /* harmless if values equal */
  274.     {
  275.         step = -step;            /* invert */
  276.     }
  277.  
  278.     sprintf (format, (width ? "%%%dd" : "%%d"), width);
  279.     sep = lflag ? ' ' : '\n';
  280.  
  281. /*
  282.  * PRINT NUMBERS:
  283.  */
  284.  
  285.     if (rflag)
  286.         PrintRandom (value1, value2, format, sep);
  287.     else
  288.     {
  289.         REG int forward = (step > 0);
  290.  
  291.         printf (format, value1);
  292.  
  293.         while (forward ? ((value1 += step) <= value2)
  294.                : ((value1 += step) >= value2))
  295.         {
  296.         putchar (sep);
  297.         printf (format, value1);
  298.         }
  299.     }
  300.  
  301.     putchar ('\n');        /* finish last line */
  302.     exit (0);
  303.  
  304. } /* main */
  305.  
  306.  
  307. /************************************************************************
  308.  * P R I N T   R A N D O M
  309.  *
  310.  * Given value limits, print format, leading separator, and global step size
  311.  * (positive or negative matching value limits), print numbers in random
  312.  * order.  Don't print the trailing newline for the last line.
  313.  */
  314.  
  315. PROC PrintRandom (value1, value2, format, sep)
  316. REG    int    value1;        /* base limit    */
  317.     int    value2;        /* end limit    */
  318. REG    char    *format;    /* how to print    */
  319. REG    char    sep;        /* leading char    */
  320. {
  321. REG    int    remain = (value2 - value1) / step;
  322. REG    int    count  = remain + 1;    /* total to print    */
  323. REG    int    *done;            /* this number printed?    */
  324. REG    int    which;            /* index in done[]    */
  325.  
  326. /*
  327.  * INITIALIZE:
  328.  */
  329.  
  330.     if ((done = (int *) calloc (count, sizeof (int))) == (int *) NULL)
  331.         Error ("calloc %d integers failed", count);
  332.  
  333.     srand48 (time ((int *) 0) + getpid() + getuid() + getgid());
  334.  
  335.     done [which = (lrand48() % count)] = TRUE;
  336.     printf (format, value1 + (which * step));    /* first one */
  337.  
  338. /*
  339.  * PRINT RANDOM NUMBERS:
  340.  */
  341.  
  342.     while (remain-- > 0)            /* more to do */
  343.     {
  344.         which = lrand48() % count;        /* not *precisely* random */
  345.  
  346.         while (done [which])        /* already taken */
  347.         {
  348.         if (--which < 0)        /* wrap around */
  349.             which = count - 1;
  350.         }
  351.  
  352.         done [which] = TRUE;
  353.         putchar (sep);
  354.         printf (format, value1 + (which * step));
  355.     }
  356.  
  357. } /* PrintRandom */
  358.  
  359.  
  360. /************************************************************************
  361.  * U S A G E
  362.  *
  363.  * Print usage messages (char *usage[]) to stderr and exit nonzero.
  364.  * Each message is followed by a newline.
  365.  */
  366.  
  367. PROC Usage()
  368. {
  369. REG    int    which = 0;        /* current line */
  370.  
  371.     while (usage [which] != CPNULL)
  372.     {
  373.         fprintf (stderr, usage [which++], myname);
  374.         putc ('\n', stderr);
  375.     }
  376.  
  377.     exit (1);
  378.  
  379. } /* Usage */
  380.  
  381.  
  382. /************************************************************************
  383.  * E R R O R
  384.  *
  385.  * Print an error message to stderr and exit nonzero.  Message is preceded
  386.  * by "<myname>: " using global char *myname, and followed by a newline.
  387.  */
  388.  
  389. /* VARARGS */
  390. PROC Error (message, arg1, arg2, arg3, arg4)
  391.     char    *message;
  392.     long    arg1, arg2, arg3, arg4;
  393. {
  394.     fprintf (stderr, "%s: ", myname);
  395.     fprintf (stderr, message, arg1, arg2, arg3, arg4);
  396.     putc ('\n', stderr);
  397.  
  398.     exit (1);
  399.  
  400. } /* Error */
  401. SHAR_EOF
  402. if test 4958 -ne "`wc -c < 'nums.c'`"
  403. then
  404.     echo shar: error transmitting "'nums.c'" '(should have been 4958 characters)'
  405. fi
  406. fi
  407. exit 0
  408. #    End of shell archive
  409.